﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class RotatingMenu : MonoBehaviour
{

    // Applied to a panel or such. Really can be applied to any control but we're starting with a panel.
    // The controls beneath it are rotated when the panel is touch-dragged.
    // How does it work? We have a center point, obviously.
    // The buttons have to arrange themselves; we'll say there's always one at the top.
    // The buttons themselves are not rotated; their positions relative to the center are.
    // State machine?
    // Normal - nothing happens
    // User touches - now the menu floats with the user's touch
    // User releases - the menu seeks toward the nearest true position and then returns to normal.

    enum InteractionState
    {
        Normal,
        UserTouch,
        SeekValid
    }

    InteractionState currentInteractionState = InteractionState.SeekValid;
    Vector2 lastUserTouch;
    Vector2 panelCenter;

    float currentRotation = 0;

    List<dfPanel> rotatingControls = new List<dfPanel>();
    List<dfButton> rotatingButtons = new List<dfButton>();
    List<float> validRotations = new List<float>();
    public int selectedControlIndex = 0;

    public float adjustDegreesPerMS = 10;

    private dfPanel myPanel = null;

    // Use this for initialization
    void Start()
    {
        myPanel = GetComponent<dfPanel>();

        foreach (Transform child in this.transform)
        {
            dfPanel childPanel = child.GetComponent<dfPanel>();
            if (childPanel != null)
            {
                rotatingControls.Add(childPanel);
                rotatingButtons.Add(childPanel.transform.GetChild(0).GetComponent<dfButton>());
            }
        }

        if (rotatingControls.Count > 0)
        {
            rotatingButtons[0].Focus();
            float itemArc = 360f / rotatingControls.Count;

            for (float f = 0; f < 360; f += itemArc) validRotations.Add(f);
        }
        else
        {
            validRotations.Add(0);
        }

        float averageControlDistance = 0.0f;

        for (int c = 0; c < rotatingControls.Count; c++)
        {
            averageControlDistance += rotatingControls[c].Position.magnitude;
        }
        averageControlDistance /= rotatingControls.Count;

        for (int c = 0; c < rotatingControls.Count; c++)
        {
            Vector2 sourceVector = new Vector2(0, averageControlDistance);
            Quaternion controlRotation = Quaternion.AngleAxis(validRotations[c], transform.forward);
            sourceVector = controlRotation * sourceVector;
            rotatingControls[c].Position = sourceVector;
        }


        dfPanel panel = GetComponent<dfPanel>();

        panelCenter = new Vector2(panel.Width / 2, panel.Height / 2);
        print("panelCenter is " + panelCenter);
        print("Panel's position is " + panel.Position);
        print("Panel's relative position is " + panel.RelativePosition);
        print("Panel's absolute position is " + panel.GetAbsolutePosition());
        print("Panel's width is " + panel.Width);
        print("Panel's height is " + panel.Height);

        //foreach (dfPanel rotatingControl in rotatingControls)
        //{
        //    print("Button's position is " + rotatingControl.Position);
        //    print("Button's relative position is " + rotatingControl.RelativePosition);
        //}
    }

    // Update is called once per frame
    void Update()
    {

        switch (currentInteractionState)
        {
            case InteractionState.SeekValid:
                if (currentInteractionState == InteractionState.SeekValid)
                {
                    // Find the closest valid position
                    // currentRotation is in degrees and is between 0 and 360
                    int closestPositionIndex = Mathf.RoundToInt(currentRotation / (360 / validRotations.Count));
                    if (closestPositionIndex >= validRotations.Count) closestPositionIndex -= validRotations.Count;

                    // degrees per millisecond * 1000 milliseconds per degree = degrees per second
                    float newAngle = Mathf.MoveTowardsAngle(currentRotation, validRotations[closestPositionIndex], adjustDegreesPerMS * 1000 * Time.deltaTime);
                    if (newAngle == currentRotation)
                    {
                        currentInteractionState = InteractionState.Normal;
                        selectedControlIndex = rotatingControls.Count - 1 - closestPositionIndex;
                        selectedControlIndex++;
                        if (selectedControlIndex >= rotatingControls.Count) selectedControlIndex -= rotatingControls.Count;
                    }
                    else
                    {
                        AdjustMenuRotation(newAngle - currentRotation);
                    }

                }
                break;
            case InteractionState.Normal:
                        dfPanel zeroPanel = rotatingControls[selectedControlIndex];

                        for (int i = 0; i < rotatingButtons.Count; i++)
                        {
                            if (i == selectedControlIndex)
                            {
                                if (!rotatingButtons[i].HasFocus) rotatingButtons[i].Focus();
                                if (!rotatingButtons[i].IsEnabled) rotatingButtons[i].IsEnabled = true;

                                rotatingButtons[i].IsEnabled = true;
                            }
                            else
                            {
                                rotatingButtons[i].IsEnabled = false;
                            }
                        }
                break;
        }




    }

    public void OnStartPressed(dfControl control, dfMouseEventArgs mouseEvent)
    {
    }



    public void OnMouseDown(dfControl control, dfMouseEventArgs mouseEvent)
    {
        mouseEvent.Use();

        // Add event handler code here
        currentInteractionState = InteractionState.UserTouch;

        lastUserTouch = control.GetHitPosition(mouseEvent) - panelCenter;
        //print("MouseDown at " + lastUserTouch);
    }

    public void OnMouseMove(dfControl control, dfMouseEventArgs mouseEvent)
    {
        if (currentInteractionState == InteractionState.UserTouch)
        {
            // Free rotate based on the change
            Vector2 currentUserTouch = control.GetHitPosition(mouseEvent) - panelCenter;
            //print("MouseMove to " + currentUserTouch);

            float angleBetween = Vector3.Angle(lastUserTouch, currentUserTouch);    // returns in degrees

            if (angleBetween > 0.001f)
            {
                float lastTheta = Mathf.Atan2(lastUserTouch.y, lastUserTouch.x);
                float currentTheta = Mathf.Atan2(currentUserTouch.y, currentUserTouch.x);
                if (currentTheta - lastTheta > 0)
                {
                    // Current theta is larger
                    angleBetween *= -1;
                }
                else
                {
                    // Previous theta was larger
                }
            }

            lastUserTouch = currentUserTouch;

            AdjustMenuRotation(angleBetween);

        }
    }

    private void AdjustMenuRotation(float degrees)
    {
        currentRotation += degrees;
        if (currentRotation >= 360) currentRotation -= 360;
        if (currentRotation < 0) currentRotation += 360;
        Quaternion rotateByAngle = Quaternion.AngleAxis(degrees, transform.forward);   // Supposed to also be degrees
        foreach (dfPanel rotatingControl in rotatingControls)
        {
            rotatingControl.Position = rotateByAngle * rotatingControl.Position;
        }

    }

    public void OnMouseUp(dfControl control, dfMouseEventArgs mouseEvent)
    {
        currentInteractionState = InteractionState.SeekValid;
    }


    public void OnGUI()
    {
        //GUI.Label(new Rect(400, 100, 300, 100), "I think rotation is at " + currentRotation + ", index is " + selectedControlIndex);
    }




}